﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Conversion_Script
{
    public static class Landscape
    {
        private static ASCII forestbiomass;
        public static ASCII ForestBiomass
        {
            get
            {
                return forestbiomass;
            }
        }
        

        private static ASCII landUsemap;
        private static Matrix landusecodes;
        public static string[] LandUseNames
        {
            get
            {
                return ArrayOperations.Remove(landusecodes.GetColumn(0), 0);
            }
        }
      
        private static ASCII[] outputvariables;
        const int Multiplactive=100000;
        private static Random rnd= new Random();
        private static int LandScapeYear;

        public static ASCII[] Outputvariables
        {
            get
            {
                return outputvariables;
            }
        
        }

        
        public static ASCII LandUseMap
        {
            get
            {
                return landUsemap;
            }
        }
        
        static public void Simulate(string fnSettings)
        {
            try
            {
                Initialize(fnSettings);
               
                int Tstepcnt = 0;
                for (LandScapeYear = 0; LandScapeYear < int.Parse(Settings.Get(KeyWords.Simulationlength)); LandScapeYear++)
                {
                    System.Console.WriteLine("LandScapeYear =" + LandScapeYear);
                    SandWatch.Update();
                    try
                    {
                         
                        if (LandScapeYear > 0)
                        {
                            LandUseTransitions.ImplementLandUseTransition();
                        }
                         
                        UpdateSimulationValues(LandScapeYear);
                        UpdateForestTypes(LandScapeYear);
                        
                        IncrementYear();

                        if (LandScapeYear == Tstepcnt)
                        {
                            Output.WriteOutput(LandScapeYear);
                            Tstepcnt += int.Parse(Settings.Get(KeyWords.TimeStep));
                        }
                    }
                    catch (System.Exception e)
                    {
                        throw e;
                    }
                }
                System.Console.WriteLine();
           
            }
            catch (System.Exception e)
            {
                throw new System.Exception("Error simulating " + fnSettings + " " + e.Message);
            }
        }

        public static void Initialize(string fnSettings)
        {
            Settings.Initialize(fnSettings);
            System.Console.Write(fnSettings);

            Output.ClearFiles(Settings.Get(KeyWords.Scenarioname));

            SandWatch.Initialize();

            landUsemap = new ASCII(Settings.Get(KeyWords.InitialLandUse));
            landusecodes = new Matrix(Settings.Get(KeyWords.InitialLandUse).Replace("asc", "txt"));

            forestbiomass = new ASCII(Settings.Get(KeyWords.ForestBiomass));

            if (forestbiomass.HasEqualDimensions(landUsemap) == false)
            {
                throw new System.Exception("Dimensions of " + Settings.Get(KeyWords.InitialLandUse) + " and " + Settings.Get(KeyWords.ForestBiomass) +" should be identical");
            }
            
            CO2FixSimulations.Initialize();

            
            outputvariables = new ASCII[CO2FixSimulations.VariableLabels.Length];
            for (int var = 0; var < CO2FixSimulations.VariableLabels.Length; var++)
            {
                outputvariables[var] = new ASCII(LandUseMap);
            }
            outputvariables[CO2FixSimulations.VarIndexBiomC] = new ASCII(Settings.Get(KeyWords.ForestBiomass));

            CO2FixSimulations.SetInitialCo2FixYear();

           

            

            LandUseTransitions.Initialize();
           
        }
        public static void UpdateForestTypes(int year)
        {
            for (int r = 0; r < landUsemap.Nrows; r++)
            {
                for (int c = 0; c < landUsemap.Ncols; c++)
                {
                    if (landUsemap[r, c] == 1 || landUsemap[r, c] == 2)
                    {
                        float value = float.Parse(CO2FixSimulations.CO2FIX_simulationvalues[landUsemap[r, c]].GetValue(CO2FixSimulations.Co2year[r, c] + 1, KeyWords.BiomC));
                        if (value < float.Parse(Settings.Get(KeyWords.ForestDegradationTreshold)))
                        {
                            Landscape.LandUseMap[r, c] = 2;
                        }
                        else Landscape.LandUseMap[r, c] = 1;
                    }
                }
            }
        }
        public static void UpdateSimulationValues(int year)
        {
            try
            {
                for (int r = 0; r < landUsemap.Nrows; r++)
                {
                    for (int c = 0; c < landUsemap.Ncols; c++)
                    {
                        for (int var = 0; var < CO2FixSimulations.VariableLabels.Length; var++)
                        {
                            float value = float.Parse(CO2FixSimulations.CO2FIX_simulationvalues[landUsemap[r, c]].GetValue(CO2FixSimulations.Co2year[r, c] + 1, var + 1));
                            outputvariables[var][r, c] = (int)Math.Round(value, 0);

                            

                        }

                    }
                }
            }
            catch (System.Exception e)
            {
                throw new System.Exception("UpdateSimulationValues\t" + e.Message);
            }
        }

        public static float GetBiomass(int LandUseType, int t)
        {
            return float.Parse(CO2FixSimulations.CO2FIX_simulationvalues[LandUseType].GetValue(t + 1, KeyWords.BiomC));
        }
        public static float GetProducts(int LandUseType, int t)
        {
            return float.Parse(CO2FixSimulations.CO2FIX_simulationvalues[LandUseType-1].GetValue(t + 1, KeyWords.Products)); // +1 for the hdr and +1 because products are registered the next year
        }
        public static int GetTimeWhenBiomassFirstOccurs(int LandUseType, string Label, float Value)
        {
            int MaxTime = CO2FixSimulations.SimLength[LandUseType] - Settings.GetSimulationLength();

            for (int t = 0; t < MaxTime; t++)
            {
                float CO2SimulationValue = float.Parse(CO2FixSimulations.CO2FIX_simulationvalues[LandUseType].GetValue(t + 1, Label));
                if (CO2SimulationValue >= Value) return t;
            }
            throw new System.Exception("Cannot itialize time for  "+ Label +" " + Value);
        }
        public static int GetInitialTime(int r, int c)
        {
            int MinTime = 0;

            if (LandUseMap[r, c] == LandUseMap.NODATA_value) return 0;

            int MaxTime = CO2FixSimulations.SimLength[LandUseMap[r, c]] - Settings.GetSimulationLength();
            int t = (int)Math.Round(rnd.NextDouble() * (MaxTime - MinTime), 0);

            if (Landscape.ForestBiomass[r, c] == 0) return t;

            // Searched biomass 
            int B = Landscape.ForestBiomass[r, c];

           

            for (int i =0;i < 1e5  ;i++ )
            {
                if ((t < 1) || (t >= MaxTime))  t = 1;

                int nextB = (int)Math.Round(GetBiomass(LandUseMap[r, c], t + 1));
                int prevB = (int)Math.Round(GetBiomass(LandUseMap[r, c], t));

                //if (Landscape.LandUseMap[r, c] == 3)
                //{
                //    System.Console.WriteLine(nextB);
                //}

                if ((nextB >= B && prevB <= B))
                {
                    if (GetProducts(LandUseMap[r, c], t) == 0)
                    {
                        return t;
                    }
                }
                
                t++;
                
               
            }
            throw new System.Exception("Cannot find B = " + B + " in " + Landscape.LandUseNames[Landscape.LandUseMap[r, c]]);

        }
              
        
         
        public static void IncrementYear()
        {
            try
            {
                for (int r = 0; r < CO2FixSimulations.Co2year.Nrows; r++)
                {
                    for (int c = 0; c < CO2FixSimulations.Co2year.Ncols; c++)
                    {
                        CO2FixSimulations.Co2year[r, c]++;
                    }
                }
            }
            catch (System.Exception e)
            {
                throw new System.Exception("IncrementYear\t" + e.Message);
            }

        }
        

        
     
        

        
         
    }
}
